package com.qtz.q6iflyspeech;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.os.Environment;
import android.util.Base64;
import android.widget.Toast;

import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.qtz.q6iflyspeech.util.JsonParser;
import com.qtz.q6iflyspeech.util.Speex;
import com.unity3d.player.UnityPlayer;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 讯飞语音sdk
 * Created by hy on 2017/4/4.
 */
public class Q6IflySpeech {
    static Q6IflySpeech instance = null;
    SpeechRecognizer mIat;
    String mSpeechRecRelt = "";
    String mSpeechRecWavPath;
    AudioTrack mAudioPlayer = null;
    Timer mPlayFinishTimer = null;
    TimerTask mPlayFinishTimerTask = null;
    ByteArrayOutputStream mOutputStream = null;
    int mCompressLevel = 1;
    String mLanguage = "zh_cn"; //语言：简体中文：zh_cn（默认）美式英文：en_us
    String mAccent = "mandarin"; //方言：普通话：mandarin(默认) 粤 语：cantonese 四川话：lmz

    public Q6IflySpeech() {
        instance = this;

        Speex.init();

        mSpeechRecWavPath = Environment.getExternalStorageDirectory()+"/q6msc/iat.wav";
        mIat = SpeechRecognizer.createRecognizer(UnityPlayer.currentActivity.getApplicationContext(), mInitListener);

        UnityPlayer.UnitySendMessage("GameManager", "SetSpeechRecWavPath", mSpeechRecWavPath);
    }

    public static Q6IflySpeech instance() {
        if(instance == null){
            instance = new Q6IflySpeech();
        }
        return instance;
    }

    public void StartSpeechRec() {
        CloseOutputStream();
        mOutputStream = new ByteArrayOutputStream();

        mIat.setParameter(SpeechConstant.DOMAIN, "iat");
        mIat.setParameter(SpeechConstant.ACCENT, mAccent);
        mIat.setParameter(SpeechConstant.LANGUAGE, mLanguage);
        mIat.setParameter(SpeechConstant.KEY_SPEECH_TIMEOUT, "4000");
        mIat.setParameter(SpeechConstant.VAD_EOS, "2000");
        mIat.setParameter(SpeechConstant.ASR_PTT, "0");
        mIat.setParameter(SpeechConstant.SAMPLE_RATE, "8000");
        //mIat.setParameter(SpeechConstant.AUDIO_FORMAT,"wav");
        //mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, mSpeechRecWavPath);
        if (mSpeechRecRelt != "") {
            mSpeechRecRelt = "";
        }
        int ret = mIat.startListening(mRecoListener);
    }

    public void StopSpeechRec() {
        CloseOutputStream();
        mIat.stopListening();
    }

    public void CancelSpeechRec() {
        CloseOutputStream();
        mIat.cancel();
    }

    public void PlayAudio(byte[] audioData, float volume) {
        if(audioData == null) {
            return;
        }
        StopPlayAudio();

        byte[] bytes = new byte[audioData.length * 100]; //compress为1时的压缩率大概为33倍，设置100倍缓存区应该够用了
        short[] rate = new short[1];

        //speex 解压
        int decSize = Speex.decode(audioData, bytes, audioData.length, rate);

        mAudioPlayer = new AudioTrack(AudioManager.STREAM_MUSIC, rate[0],
                AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT,
                decSize,
                AudioTrack.MODE_STATIC);
        mAudioPlayer.setStereoVolume(volume, volume);
        mAudioPlayer.write(bytes, 0, decSize);
        mAudioPlayer.play();

        //计算大概播放时间
        short playTime = (short) ((3.5 * bytes.length) / (rate[0] * 16));

        //Log.d("Q6IflySpeech", "=======================PlayAudio start playTime=" + playTime);
        //final String msg = "PlayAudio playTime=" + playTime + " encodeSize=" + audioData.length + "decodeSize=" + decSize;

        if (playTime > 0) {
            mPlayFinishTimer = new Timer();
            mPlayFinishTimerTask = new TimerTask() {
                @Override
                public void run() {
                    //Log.d("Q6IflySpeech", "=======================PlayAudio finish");
                    StopPlayAudio();
                    UnityPlayer.UnitySendMessage("GameManager", "OnAudioComplete", "");
                    //Log.d("Q6IflySpeech", "=======================PlayAudio finish11");
                }
            };
            mPlayFinishTimer.schedule(mPlayFinishTimerTask, playTime*1000);
        } else {
            StopPlayAudio();
            UnityPlayer.UnitySendMessage("GameManager", "OnAudioComplete", "");
        }
    }

    public void PlayAudioBase64(String audioDataBase64) {
        //base64 解码
        byte[] audioData = Base64.decode(audioDataBase64, Base64.DEFAULT);
        PlayAudio(audioData, 1);
    }

    public void StopPlayAudio() {
        if (mPlayFinishTimer != null){
            mPlayFinishTimer.cancel();
            mPlayFinishTimer = null;
        }
        if (mPlayFinishTimerTask != null){
            mPlayFinishTimerTask.cancel();
            mPlayFinishTimerTask = null;
        }
        if (mAudioPlayer != null){
            mAudioPlayer.stop();
            mAudioPlayer.release();
            mAudioPlayer = null;
        }
    }

    private InitListener mInitListener = new InitListener() {
        @Override
        public void onInit(int arg0) {
            //UnityPlayer.UnitySendMessage("GameManager", "OnInitSpeechRec", "mInitListener");
            if (arg0 != 0) {
                Toast.makeText(UnityPlayer.currentActivity, "语音听写初始化失败", Toast.LENGTH_SHORT).show();
            }
        }
    };

    private RecognizerListener mRecoListener = new RecognizerListener() {
        @Override
        public void onVolumeChanged(int arg0, byte[] arg1) {
            // TODO Auto-generated method stub
            //处理数据
            try {
                if (mOutputStream != null && arg1 != null) {
                    //Log.d("Q6IflySpeech", "=======================onVolumeChanged data out byteLen=" + arg1.length);
                    mOutputStream.write(arg1);
                }
            } catch (IOException e) {

            }
            UnityPlayer.UnitySendMessage("GameManager", "OnVolumeChanged", Integer.toString(arg0));
        }

        @Override
        public void onResult(RecognizerResult arg0, boolean arg1) {
            // TODO Auto-generated method stub
            mSpeechRecRelt = mSpeechRecRelt + JsonParser.parseIatResult(arg0.getResultString());
            if(arg1){
                UnityPlayer.UnitySendMessage("GameManager", "OnSpeechRecResult", mSpeechRecRelt);
            }
        }

        @Override
        public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onError(SpeechError arg0) {
            // TODO Auto-generated method stub
            CloseOutputStream();
            UnityPlayer.UnitySendMessage("GameManager", "OnSpeechRecError", arg0.getPlainDescription(true));
        }

        @Override
        public void onEndOfSpeech() {
            // TODO Auto-generated method stub
            UnityPlayer.UnitySendMessage("GameManager", "OnSpeechRecEnd", "");
        }

        @Override
        public void onBeginOfSpeech() {
            // TODO Auto-generated method stub
            UnityPlayer.UnitySendMessage("GameManager", "OnSpeechRecBegin", "");
        }
    };

    void CloseOutputStream(){
        try {
            if(mOutputStream != null) {
                mOutputStream.close();
                mOutputStream = null;
            }
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }

    public void SetCompressLevel(int level) {
        mCompressLevel = level;
    }

    public void SetLanguage(String language) {
        mLanguage = language;
    }

    public void SetAccent(String accent) {
        mAccent = accent;
    }

    public void ReadAudioData(){
        if(mOutputStream != null) {
            byte[] bytes = mOutputStream.toByteArray();
            if (bytes.length > 0) {
                byte[] encoded = new byte[bytes.length];

                //speex 压缩
                int getSize = Speex.encode(bytes, encoded, bytes.length, mCompressLevel);

                ByteArrayOutputStream out = new ByteArrayOutputStream();
                out.write(encoded, 0, getSize);
                byte[] encodeBytes = out.toByteArray();

                //Log.d("Q6IflySpeech", "=======================SubmitAudioData byteLen=" + bytes.length + " after speex encode getSize=" + getSize);

                String audioDataBase64 = Base64.encodeToString(encodeBytes, Base64.DEFAULT);

                UnityPlayer.UnitySendMessage("GameManager", "OnAudioDataRead", audioDataBase64);
            }
        }
        CloseOutputStream();
    }

    public void destroy() {
        StopPlayAudio();
        CloseOutputStream();
        if(null != mIat) {
            // 退出时释放连接
            mIat.cancel();
            mIat.destroy();
            mIat = null;
        }
    }
}
